package com.komorebi.friends.job;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.komorebi.friends.constant.RedisConstant;
import com.komorebi.friends.mapper.UserMapper;
import com.komorebi.friends.model.entity.User;
import com.komorebi.friends.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.client.RedisClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Component
@Slf4j
public class PreCacheJob {
    
    //如果用户过多，可以设置一个重点用户列表，定时更校招其推荐列表缓存
    //不写死在代码里
    
    @Resource
    private UserMapper userMapper;
    
    @Resource
    private UserService userService;
    
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private RedissonClient redissonClient;

    //每天3点更新匹配列表
    @Scheduled(cron = "0 0 3 * * ? ")
    public void doCacheMatch(){
        //获取锁，让一台服务器执行
        RLock lock = redissonClient.getLock(RedisConstant.REDIS_MATCH_PRECACHE_LOCK_PREFIX);
        try {
            boolean b = lock.tryLock(0, -1, TimeUnit.MILLISECONDS);
            if(b){
                //把所有用户的匹配表放在缓存里，每个用户匹配个20个
                List<User> list = userService.list();
                for (User user : list) {
                    List<User> matchUsers = userService.getMatchUsers(20L, user);
                    //写入缓存，直接使用opsForValue
                    String key = RedisConstant.REDIS_MATCH_INFO_PREFIX + user.getId();
                    try {
                        redisTemplate.opsForValue().set(key,matchUsers,RedisConstant.MATCH_INFO_TTL,TimeUnit.DAYS);
                    } catch (Exception e) {
                        e.printStackTrace();
                        log.error("定时任务写redis匹配信息失败：{}",user.getId());
                    }
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            log.error("定时任务获取写匹配信息锁失败");
        } finally {
            if(lock.isHeldByCurrentThread()){
                log.info("释放写匹配信息锁");
                lock.unlock();
            }
        }
    }
    
    //每天4点执行缓存推荐列表
    @Scheduled(cron = "0 0 4 * * ? ")
    public void doCacheRecommend(){
        //获取锁，只让获得锁的一台服务器执行
        RLock lock = redissonClient.getLock(RedisConstant.REDIS_RECOMMEND_PRECACHE_LOCK_PREFIX);

        try {
            boolean b = lock.tryLock(0, -1, TimeUnit.MILLISECONDS);
            if (b) {
                // 获得用户列表
                QueryWrapper<User> queryWrapper = new QueryWrapper<>();
                List<User> users = userMapper.selectList(queryWrapper);
                for (User user : users) {
                    Long userId = user.getId();
                    // 2.数据库分页
                    // 2.1用户信息分页
                    Page<User> userPage = userService.page(new Page<>(1, 20), queryWrapper);
                    // 2.2用户安全信息
                    List<User> safetyUsers = userPage.getRecords().stream().map(u1 -> userService.getSafetyUser(u1)).collect(Collectors.toList());
                    userPage.setRecords(safetyUsers);
                    // 2.3写入缓存
                    String key = RedisConstant.REDIS_RECOMMEND_INFO_PREFIX + userId;
                    try {
                        redisTemplate.opsForValue().set(key,userPage, RedisConstant.RECOMMEND_INFO_TTL, TimeUnit.DAYS);
                    } catch (Exception e) {
                        log.error("recommendUser redis set error", e);
                    }
                }
            }
        } catch (InterruptedException e) {
            log.error("doCacheRecommend error", e);
        } finally {
            //只能释放自己的锁
            if(lock.isHeldByCurrentThread()){
                log.info("释放锁:"+Thread.currentThread().getName());
                lock.unlock();
            }
        }


    }
    
}
